/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: 音频采集模块 - 通过I2S+DMA LLI采集数字麦克风数据
 */

#include "little_test.h"
#include "i2s.h"
#include "dma.h"
#include "osal_debug.h"
#include "osal_task.h"
#include "osal_semaphore.h"
#include "securec.h"
#include <stdlib.h>
#include <string.h>

// DMA LLI节点结构
typedef struct {
    dma_lli_transfer_config_t config;
    struct dma_lli_transfer_config_t *next;
} dma_lli_node_t;

/**
 * @brief DMA传输完成回调函数
 * @param channel DMA通道号
 * @param transfer_stat 传输状态
 * @param user_data 用户数据
 */
static void audio_capture_dma_callback(uint8_t channel, dma_transfer_stat_t transfer_stat, uintptr_t user_data)
{
    audio_capture_t *capture = (audio_capture_t *)user_data;
    
    if (capture == NULL || !capture->initialized) {
        return;
    }

    if (transfer_stat == DMA_TRANSFER_STAT_SUCC) {
        // DMA传输成功，通知处理任务
        capture->current_buffer_index = (capture->current_buffer_index + 1) % LITTLE_TEST_BUFFER_COUNT;
        capture->frames_captured++;
        
        // 释放信号量通知有新数据
        osal_sem_up(&capture->data_ready_sem);
    } else {
        // DMA传输错误
        capture->error_count++;
        osal_printk("[AUDIO_CAPTURE] DMA transfer error: %d\n", transfer_stat);
    }
}

/**
 * @brief 初始化I2S配置
 * @param capture 音频采集结构体指针
 * @return 0成功，其他失败
 */
static int audio_capture_init_i2s(audio_capture_t *capture)
{
    i2s_config_t i2s_config = {0};
    
    // 配置I2S参数
    i2s_config.drive_mode = I2S_MASTER_MODE;  // 主机模式
    i2s_config.transfer_mode = I2S_STD_MODE;  // 标准模式
    i2s_config.data_width = I2S_DATA_WIDTH_16;  // 16位数据
    i2s_config.channels_num = I2S_CHANNELS_2;   // 双声道（但只有一个声道有数据）
    i2s_config.sampling_frequency = LITTLE_TEST_SAMPLE_RATE;  // 采样率16kHz
    i2s_config.clk_edge = I2S_CLK_EDGE_RISE;   // 上升沿采样
    i2s_config.div_number = 0;  // 自动计算分频
    
    // 初始化I2S
    errcode_t ret = uapi_i2s_init(I2S_BUS_0, &i2s_config);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to init I2S: 0x%x\n", ret);
        return -1;
    }
    
    // 设置I2S接收模式
    ret = uapi_i2s_set_mode(I2S_BUS_0, I2S_MODE_RX);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to set I2S RX mode: 0x%x\n", ret);
        uapi_i2s_deinit(I2S_BUS_0);
        return -1;
    }
    
    osal_printk("[AUDIO_CAPTURE] I2S initialized: %d Hz, 16-bit, 2-ch\n", LITTLE_TEST_SAMPLE_RATE);
    return 0;
}

/**
 * @brief 初始化DMA LLI链表
 * @param capture 音频采集结构体指针
 * @return 0成功，其他失败
 */
static int audio_capture_init_dma_lli(audio_capture_t *capture)
{
    errcode_t ret;
    uint32_t i;
    
    // 分配DMA LLI节点
    capture->dma_lli_nodes = (dma_lli_node_t *)malloc(LITTLE_TEST_BUFFER_COUNT * sizeof(dma_lli_node_t));
    if (capture->dma_lli_nodes == NULL) {
        osal_printk("[AUDIO_CAPTURE] Failed to allocate DMA LLI nodes\n");
        return -1;
    }
    
    // 配置每个DMA LLI节点
    for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
        dma_lli_node_t *node = &capture->dma_lli_nodes[i];
        
        // 配置DMA传输参数
        node->config.src_addr = (uintptr_t)uapi_i2s_get_data_addr(I2S_BUS_0);  // I2S数据寄存器地址
        node->config.dest_addr = (uintptr_t)capture->dma_buffers[i];  // 目标缓冲区地址
        node->config.length = LITTLE_TEST_BUFFER_SIZE;  // 传输长度
        node->config.src_width = DMA_TRANSFER_WIDTH_16;  // 源数据宽度16位
        node->config.dest_width = DMA_TRANSFER_WIDTH_16;  // 目标数据宽度16位
        node->config.burst_length = DMA_BURST_LENGTH_4;  // 突发长度
        node->config.src_increment = DMA_ADDRESS_INC_NO;  // 源地址不递增（寄存器）
        node->config.dest_increment = DMA_ADDRESS_INC_YES;  // 目标地址递增
        node->config.priority = DMA_CHANNEL_PRIORITY_HIGH;  // 高优先级
        node->config.trans_type = DMA_TRANS_PERIPHERAL_TO_MEMORY_DMA;  // 外设到内存
        node->config.trans_dir = DMA_TRANSFER_DIR_PERIPHERAL_TO_MEM;  // 传输方向
        
        // 设置链表指针（循环链表）
        if (i == LITTLE_TEST_BUFFER_COUNT - 1) {
            node->next = &capture->dma_lli_nodes[0].config;  // 最后一个指向第一个
        } else {
            node->next = &capture->dma_lli_nodes[i + 1].config;  // 指向下一个
        }
    }
    
    // 申请DMA通道
    ret = uapi_dma_open();
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to open DMA: 0x%x\n", ret);
        free(capture->dma_lli_nodes);
        return -1;
    }
    
    // 配置DMA通道
    dma_channel_config_t dma_config = {0};
    dma_config.src_handshaking = DMA_HANDSHAKING_I2S_RX;  // I2S接收握手
    dma_config.dest_handshaking = DMA_HANDSHAKING_MAX;    // 内存不需要握手
    dma_config.trans_type = DMA_TRANS_PERIPHERAL_TO_MEMORY_DMA;
    dma_config.trans_dir = DMA_TRANSFER_DIR_PERIPHERAL_TO_MEM;
    dma_config.priority = DMA_CHANNEL_PRIORITY_HIGH;
    
    ret = uapi_dma_configure_channel(capture->dma_channel, &dma_config);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to configure DMA channel: 0x%x\n", ret);
        uapi_dma_close();
        free(capture->dma_lli_nodes);
        return -1;
    }
    
    // 注册DMA回调函数
    ret = uapi_dma_register_interrupt(capture->dma_channel, audio_capture_dma_callback, (uintptr_t)capture);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to register DMA interrupt: 0x%x\n", ret);
        uapi_dma_close();
        free(capture->dma_lli_nodes);
        return -1;
    }
    
    osal_printk("[AUDIO_CAPTURE] DMA LLI initialized: %d buffers, channel %d\n", 
                LITTLE_TEST_BUFFER_COUNT, capture->dma_channel);
    return 0;
}

/**
 * @brief 初始化音频采集模块
 * @param capture 音频采集结构体指针
 * @return 0成功，其他失败
 */
int audio_capture_init(audio_capture_t *capture)
{
    uint32_t i;
    errcode_t ret;
    
    if (capture == NULL) {
        osal_printk("[AUDIO_CAPTURE] Invalid capture pointer\n");
        return -1;
    }

    // 初始化结构体
    memset_s(capture, sizeof(audio_capture_t), 0, sizeof(audio_capture_t));
    
    // 分配DMA缓冲区
    for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
        capture->dma_buffers[i] = (uint8_t *)malloc(LITTLE_TEST_BUFFER_SIZE);
        if (capture->dma_buffers[i] == NULL) {
            osal_printk("[AUDIO_CAPTURE] Failed to allocate DMA buffer %d\n", i);
            // 释放已分配的缓冲区
            for (uint32_t j = 0; j < i; j++) {
                free(capture->dma_buffers[j]);
            }
            return -1;
        }
        // 清零缓冲区
        memset_s(capture->dma_buffers[i], LITTLE_TEST_BUFFER_SIZE, 0, LITTLE_TEST_BUFFER_SIZE);
    }
    
    // 创建信号量
    ret = osal_sem_init(&capture->data_ready_sem, 0);
    if (ret != OSAL_SUCCESS) {
        osal_printk("[AUDIO_CAPTURE] Failed to create semaphore\n");
        for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
            free(capture->dma_buffers[i]);
        }
        return -1;
    }
    
    // 设置DMA通道（假设使用通道0）
    capture->dma_channel = 0;
    capture->current_buffer_index = 0;
    capture->frames_captured = 0;
    capture->error_count = 0;
    
    // 初始化I2S
    if (audio_capture_init_i2s(capture) != 0) {
        osal_sem_destroy(&capture->data_ready_sem);
        for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
            free(capture->dma_buffers[i]);
        }
        return -1;
    }
    
    // 初始化DMA LLI
    if (audio_capture_init_dma_lli(capture) != 0) {
        uapi_i2s_deinit(I2S_BUS_0);
        osal_sem_destroy(&capture->data_ready_sem);
        for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
            free(capture->dma_buffers[i]);
        }
        return -1;
    }
    
    capture->initialized = true;
    capture->started = false;
    
    osal_printk("[AUDIO_CAPTURE] Initialized successfully\n");
    osal_printk("[AUDIO_CAPTURE] Buffer count: %d, Buffer size: %d bytes\n", 
                LITTLE_TEST_BUFFER_COUNT, LITTLE_TEST_BUFFER_SIZE);
    osal_printk("[AUDIO_CAPTURE] Frame size: %d samples (%.1f ms)\n", 
                LITTLE_TEST_FRAME_SIZE, (float)LITTLE_TEST_FRAME_SIZE * 1000.0f / LITTLE_TEST_SAMPLE_RATE);
    
    return 0;
}

/**
 * @brief 反初始化音频采集模块
 * @param capture 音频采集结构体指针
 */
void audio_capture_deinit(audio_capture_t *capture)
{
    uint32_t i;
    
    if (capture == NULL) {
        return;
    }
    
    // 停止采集
    if (capture->started) {
        audio_capture_stop(capture);
    }
    
    // 反初始化DMA
    if (capture->dma_lli_nodes != NULL) {
        uapi_dma_unregister_interrupt(capture->dma_channel);
        uapi_dma_close();
        free(capture->dma_lli_nodes);
        capture->dma_lli_nodes = NULL;
    }
    
    // 反初始化I2S
    uapi_i2s_deinit(I2S_BUS_0);
    
    // 销毁信号量
    osal_sem_destroy(&capture->data_ready_sem);
    
    // 释放DMA缓冲区
    for (i = 0; i < LITTLE_TEST_BUFFER_COUNT; i++) {
        if (capture->dma_buffers[i] != NULL) {
            free(capture->dma_buffers[i]);
            capture->dma_buffers[i] = NULL;
        }
    }
    
    capture->initialized = false;
    
    osal_printk("[AUDIO_CAPTURE] Deinitialized\n");
}

/**
 * @brief 开始音频采集
 * @param capture 音频采集结构体指针
 * @return 0成功，其他失败
 */
int audio_capture_start(audio_capture_t *capture)
{
    errcode_t ret;
    
    if (capture == NULL || !capture->initialized) {
        osal_printk("[AUDIO_CAPTURE] Invalid capture or not initialized\n");
        return -1;
    }
    
    if (capture->started) {
        osal_printk("[AUDIO_CAPTURE] Already started\n");
        return 0;
    }
    
    // 重置统计信息
    capture->current_buffer_index = 0;
    capture->frames_captured = 0;
    capture->error_count = 0;
    
    // 启动DMA LLI传输
    ret = uapi_dma_start_lli_transfer(capture->dma_channel, 
                                     &capture->dma_lli_nodes[0].config, 
                                     DMA_LLI_TRANSFER_MODE_CIRCULAR);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to start DMA LLI transfer: 0x%x\n", ret);
        return -1;
    }
    
    // 启动I2S接收
    ret = uapi_i2s_start(I2S_BUS_0);
    if (ret != ERRCODE_SUCC) {
        osal_printk("[AUDIO_CAPTURE] Failed to start I2S: 0x%x\n", ret);
        uapi_dma_stop(capture->dma_channel);
        return -1;
    }
    
    capture->started = true;
    
    osal_printk("[AUDIO_CAPTURE] Started successfully\n");
    return 0;
}

/**
 * @brief 停止音频采集
 * @param capture 音频采集结构体指针
 * @return 0成功，其他失败
 */
int audio_capture_stop(audio_capture_t *capture)
{
    if (capture == NULL || !capture->initialized) {
        return -1;
    }
    
    if (!capture->started) {
        return 0;
    }
    
    // 停止I2S
    uapi_i2s_stop(I2S_BUS_0);
    
    // 停止DMA
    uapi_dma_stop(capture->dma_channel);
    
    capture->started = false;
    
    osal_printk("[AUDIO_CAPTURE] Stopped. Captured %d frames, %d errors\n", 
                capture->frames_captured, capture->error_count);
    return 0;
}

/**
 * @brief 等待音频数据就绪
 * @param capture 音频采集结构体指针
 * @param timeout_ms 超时时间（毫秒）
 * @return 0成功，其他失败
 */
int audio_capture_wait_data(audio_capture_t *capture, uint32_t timeout_ms)
{
    if (capture == NULL || !capture->initialized || !capture->started) {
        return -1;
    }
    
    // 等待信号量
    errcode_t ret = osal_sem_down_timeout(&capture->data_ready_sem, timeout_ms);
    if (ret != OSAL_SUCCESS) {
        if (ret == OSAL_FAILURE) {
            // 超时
            return -2;
        }
        return -1;
    }
    
    return 0;
}

/**
 * @brief 获取当前可用的音频数据
 * @param capture 音频采集结构体指针
 * @param frame 输出的音频帧
 * @return 0成功，其他失败
 */
int audio_capture_get_frame(audio_capture_t *capture, audio_frame_t *frame)
{
    if (capture == NULL || !capture->initialized || frame == NULL) {
        return -1;
    }
    
    // 计算上一个完成的缓冲区索引
    uint32_t ready_buffer_index = (capture->current_buffer_index + LITTLE_TEST_BUFFER_COUNT - 1) % LITTLE_TEST_BUFFER_COUNT;
    
    // 设置音频帧信息
    frame->data = capture->dma_buffers[ready_buffer_index];
    frame->size = LITTLE_TEST_BUFFER_SIZE;
    frame->timestamp = osal_get_current_time();  // 获取当前时间戳
    frame->sequence = capture->frames_captured;
    
    return 0;
}

/**
 * @brief 获取采集统计信息
 * @param capture 音频采集结构体指针
 * @param frames_captured 输出已采集帧数
 * @param error_count 输出错误计数
 * @param current_buffer_index 输出当前缓冲区索引
 * @return 0成功，其他失败
 */
int audio_capture_get_stats(audio_capture_t *capture, 
                           uint32_t *frames_captured, 
                           uint32_t *error_count, 
                           uint32_t *current_buffer_index)
{
    if (capture == NULL || !capture->initialized) {
        return -1;
    }
    
    if (frames_captured != NULL) {
        *frames_captured = capture->frames_captured;
    }
    
    if (error_count != NULL) {
        *error_count = capture->error_count;
    }
    
    if (current_buffer_index != NULL) {
        *current_buffer_index = capture->current_buffer_index;
    }
    
    return 0;
}